grammar Antlr;

options {
  language = Java;
  output   = AST;
}

tokens {
  AST_PEARL_UNIT;
  AST_PROLOGUE;
  AST_RULES;
  AST_PREFIX_DECLARATION;
  AST_RULE;
  AST_LAZY_RULE;
  AST_ID;
  AST_DATATYPE;
  AST_LANG;
  AST_UIMA_TYPE_NAME;
  AST_BINDINGS_CLAUSE;
  AST_BINDING_DEFINITION;
  AST_NODES_CLAUSE;
  AST_NODES_DEF;
  AST_PROJECTION_OPERATOR;
  AST_CONVERTERS;
  AST_FEATURE_PATH;
  AST_FEATURE_PATH_ELEMENT;
  AST_GRAPH_CLAUSE;
  AST_JAVA_QUALIFIED_NAMED;
  AST_GRAPH;
  AST_GRAPH_TRIPLE;
  AST_GRAPH_SUBJECT;
  AST_GRAPH_PREDICATE;
  AST_GRAPH_OBJECT;
  AST_OPTIONAL;
  AST_VAR;
  AST_PLACE_HOLDER;
  AST_IRI_REF;
  AST_BLANK_NODE;
  AST_PREFIXED_NAME;
  AST_ABBR;
  AST_WHERE_CLAUSE;
  AST_WHERE_TRIPLE;
  AST_WHERE_SUBJECT;
  AST_WHERE_PREDICATE;
  AST_WHERE_OBJECT;
}

@header {
package it.uniroma2.art.coda.pearl.parser.antlr;
	import it.uniroma2.art.coda.pearl.parser.antlr.AntlrParserRuntimeException;
}

@lexer::header {
package it.uniroma2.art.coda.pearl.parser.antlr;
}

@lexer::members {
@Override
public void reportError(RecognitionException e) {
	System.out.println("&&& Lexer::reportError\n"); // DEBUG
	System.out.println(e.getClass().toString());
    	
	if (e instanceof UnwantedTokenException) {
		String text = ((UnwantedTokenException) e).getUnexpectedToken().getText();
	  int line = ((UnwantedTokenException) e).getUnexpectedToken().getLine();
	  int pos = ((UnwantedTokenException) e).getUnexpectedToken()
	      .getCharPositionInLine();
	  String msg = "Lexer error with text = " + text + " at line " + line
	      + " and char " + pos;
	  System.out.println(msg);
	  throw new AntlrParserRuntimeException(msg);
	} else if (e instanceof NoViableAltException){
	  int line = ((NoViableAltException) e).line;
	  int pos = ((NoViableAltException) e).charPositionInLine;
	  String msg = "Lexer error at line " + line
	      + " with char at position " + pos;
	  System.out.println(msg); // DEBUG
	  throw new AntlrParserRuntimeException(msg);
	}else {
	  e.printStackTrace();
	  throw new AntlrParserRuntimeException(e.toString());
	}	
}
}

@members {
@Override
public void reportError(RecognitionException e) {
	String msg = "Parser error";
	if (e instanceof UnwantedTokenException) {
		String text = ((UnwantedTokenException) e).getUnexpectedToken()
				.getText();
		int line = ((UnwantedTokenException) e).getUnexpectedToken().getLine();
		int pos = ((UnwantedTokenException) e).getUnexpectedToken()
				.getCharPositionInLine();
		msg += " with text = " + text + " at line " + line + " and char " + pos;
	} else if (e instanceof MismatchedTokenException) {
		System.out
				.println(((MismatchedTokenException) e).getLocalizedMessage()); // DEBUG
	} else {
		e.printStackTrace(); // DEBUG
	}
	//System.out.println("&&& Problem with text = "+text+" at line "+line+" and char "+pos); // da cancellare

	System.out.println(msg); // DEBUG
	throw new AntlrParserRuntimeException(msg);
	//throw new IllegalArgumentException(e);
}
}



pearlUnit
  :
  prologue rules
  -> ^(AST_PEARL_UNIT prologue rules)
  ;
  
prologue
  :
  prefixDecl* 
  -> ^(AST_PROLOGUE prefixDecl*)
  ;
  
prefixDecl
  :
  'prefix' PNAME_NS IRIREF
  -> ^(AST_PREFIX_DECLARATION PNAME_NS IRIREF)
  ;

rules
  :
  (r+=rule|r+=lazyRule)+
  -> ^(AST_RULES $r+)
  ;

rule
  :
  'rule' uimaTypeName ruleId?'{'
    bindingsClause?
    nodesClause?
    graphClause?
    whereClause?
  '}'
  -> ^(AST_RULE ^(AST_ID ruleId)? uimaTypeName bindingsClause? nodesClause? graphClause? whereClause?
  )
  ;
  
lazyRule
  :
  'lazy' 'rule' uimaTypeName ruleId '{'
    nodesClause?
  '}'
  -> ^(AST_LAZY_RULE ^(AST_ID ruleId)? uimaTypeName nodesClause?)
  ;
  
uimaTypeName
  :
  javaQualifiedName
  -> ^(AST_UIMA_TYPE_NAME javaQualifiedName)
  ;

bindingsClause
  :
  'bindings' '=' '{'
    bindingDef+
  '}'
  -> ^(AST_BINDINGS_CLAUSE bindingDef+)
  ;

bindingDef
  :
  bindingId=JAVA_IDENTIFIER featurePath ruleId
  -> ^(AST_BINDING_DEFINITION $bindingId featurePath ruleId)
  ;
  
ruleId
  :
  RULE_ID
  ;
  
RULE_ID
  :
  'id:' PN_LOCAL
  ;

nodesClause
  :
  'nodes' '=' '{'
    nodeDef+
  '}'
  -> ^(AST_NODES_CLAUSE nodeDef+)
  ;
  
nodeDef
  :
  JAVA_IDENTIFIER projectionOperator featurePath
  -> ^(AST_NODES_DEF JAVA_IDENTIFIER projectionOperator featurePath)
  ;
  
projectionOperator
  :
  'uri' converters?
  -> ^(AST_PROJECTION_OPERATOR 'uri' converters?)
  |
  'literal' '^^' iri converters?
  -> ^(AST_PROJECTION_OPERATOR 'literal' converters? ^(AST_DATATYPE iri) )
  |
  'literal' LANGTAG  converters?
  -> ^(AST_PROJECTION_OPERATOR 'literal' converters? ^(AST_LANG LANGTAG))
  |
  'literal' converters?
  -> ^(AST_PROJECTION_OPERATOR 'literal' converters?)

  ;
  
converters
  :
  '(' iri (',' iri)* ')'
  -> ^(AST_CONVERTERS iri+)
  ;

featurePath
  :
  featurePathElement ('/' featurePathElement)*
  -> ^(AST_FEATURE_PATH featurePathElement+)
  ;

featurePathElement
  :
  JAVA_IDENTIFIER ('[' INTEGER ']')?
  -> ^(AST_FEATURE_PATH_ELEMENT JAVA_IDENTIFIER INTEGER?)
  ;

graphClause
  :
  'graph' '=' graph
  -> ^(AST_GRAPH_CLAUSE graph)
  ;
 
javaQualifiedName
  :
  JAVA_IDENTIFIER ('.' JAVA_IDENTIFIER)*
  -> ^(AST_JAVA_QUALIFIED_NAMED JAVA_IDENTIFIER+)
  ;

graph
  :
  '{'
  graphElement+
  '}'
  -> ^(AST_GRAPH graphElement+)
  ;
 
 graphElement
  :
  graphTriple | optionalGraphElement
  ;
 
 optionalGraphElement
  :
  'OPTIONAL' '{' graphTriple+ '}'
  -> ^(AST_OPTIONAL graphTriple+)
  ;
 
graphTriple
  :
  graphSubject graphPredicate graphObject '.'
  -> ^(AST_GRAPH_TRIPLE graphSubject graphPredicate graphObject)
  ;
  
graphSubject
  :
  var |
  iri |
  blankNode |
  placeholder
  ;
  
graphPredicate
  :
  var |
  iri |
  abbr |
  placeholder
  ;
  
graphObject
  :
  var |
  iri |
  literal |
  blankNode |
  placeholder
  ;

var
  :
  VAR1
  -> ^(AST_VAR VAR1)
  ;
  
placeholder
  :
  VAR2 ('.' JAVA_IDENTIFIER)?
  -> ^(AST_PLACE_HOLDER VAR2 JAVA_IDENTIFIER?)
  ;
  
iri
  :
  IRIREF
  -> ^(AST_IRI_REF IRIREF)|
  prefixedName
  -> prefixedName
  ;
  
literal
  :
  'literal'
  ;
  
blankNode
  :
  BLANK_NODE_LABEL
  -> ^(AST_BLANK_NODE BLANK_NODE_LABEL)
  ;
  
prefixedName
  :
  PNAME_LN 
  -> ^(AST_PREFIXED_NAME PNAME_LN)
  |
  pn=PNAME_NS
  -> ^(AST_PREFIXED_NAME PNAME_NS)
  ;
  
abbr
  :
  'a'
  -> ^(AST_ABBR 'a')
  ;

whereClause
  :
  'where' '=' graph
  -> ^(AST_WHERE_CLAUSE graph)
  ;
  
//whereTriple
//  :
//  whereSubject wherePredicate whereObject '.'
//  -> ^(AST_WHERE_TRIPLE whereSubject wherePredicate whereObject)
//  ;

//whereSubject
//  :
//  var
//  -> ^(AST_WHERE_SUBJECT var) |
//  iri
//  -> ^(AST_WHERE_SUBJECT iri) |
//  blankNode
//  -> ^(AST_WHERE_SUBJECT blankNode)
//  ;
//  
//wherePredicate
//  :
//  var
//  -> ^(AST_WHERE_PREDICATE var) |
//  iri
//  -> ^(AST_WHERE_PREDICATE iri) |
//  abbr
//  -> ^(AST_WHERE_PREDICATE abbr)
//  ; 
//  
//whereObject
//  :
//  var
//  -> ^(AST_WHERE_PREDICATE var) |
//  iri
//  -> ^(AST_WHERE_PREDICATE iri) |
//  literal
//  -> ^(AST_WHERE_PREDICATE literal) |
//  blankNode
//  -> ^(AST_WHERE_PREDICATE blankNode)
//  ;

WS:     (' ' | '\t' | '\f' |'\r')+ {$channel=HIDDEN;};
NEWLINE:  '\n' {$channel=HIDDEN;};
COMMENT: '//' .* ('\n' | '\r') {$channel=HIDDEN;};
MULTILINE_COMMENT:  '/*' (options {greedy=false;} : .)* '*/' {$channel=HIDDEN;};
 
IRIREF
  :
  '<' (~('<' | '>' | '"' | '{' | '}' | '|' | '^' | '`' | '\u0000'..'\u0020'))* '>'
  ;
  
VAR1
  :
  '?' VARNAME
  ;

VAR2
  :
  '$' VARNAME
  ;

PNAME_NS
  :
  PN_PREFIX? ':'
  ;
  
PNAME_LN
  :
  PNAME_NS PN_LOCAL
  ;

BLANK_NODE_LABEL
  :
 // '_:' PN_LOCAL( PN_CHARS_U | '0'..'9' ) ((PN_CHARS|'.')* PN_CHARS)?
 '_:' PN_LOCAL
  ;

LANGTAG
  :
  '@' ('a'..'z'|'A'..'Z')+ ('-' ('a'..'z'|'A'..'Z'|'0'..'9')+)*
  ;

fragment
PN_LOCAL
  :
  (PN_CHARS_U | ':' | '0'..'9' | PLX ) ((PN_CHARS | '.' | ':' | PLX)* (PN_CHARS | ':' | PLX) )?
  ;

fragment
PLX
  :
  PERCENT | PN_LOCAL_ESC
  ;

fragment
PERCENT
  :
  '%' HEX HEX
  ;
  
fragment
HEX
  :
  '0'..'9' | 'A'..'F' | 'a'..'f'
  ;

fragment
PN_LOCAL_ESC
  :
  '\\' ( '_' | '~' | '.' | '-' | '!' | '$' | '&' | '\'' | '(' | ')' | '*' | '+' | ',' | ';' | '=' | '/' | '?'
  | '#' | '@' | '%' )
  ;
fragment
PN_PREFIX
  :
  PN_CHARS_BASE ((PN_CHARS/*|'.'*/)* PN_CHARS)? // Dot removed since it causes a bug in the generated Lexer
  ;

fragment
PN_CHARS_BASE
  :
  'A'..'Z' | 'a'..'z'| '\u00C0'..'\u00D6' | '\u00D8'..'\u00F6'| '\u00F8'..'\u02FF' | '\u0370'..'\u037D'|
  '\u037F'..'\u1FFF' | '\u200C'..'\u200D'| '\u2070'..'\u218F' | '\u2C00'..'\u2FEF' | '\u3001'..'\uD7FF' |
  '\uF900'..'\uFDCF' | '\uFDF0'..'\uFFFD' //TODO: add the following | [#x10000-#xEFFFF]
  ;

fragment
PN_CHARS_U
  :
  PN_CHARS_BASE | '_'
  ;

fragment
PN_CHARS
  :
  PN_CHARS_U | '-' | '0'..'9' | '\u00B7' | '\u0300'..'\u036F' | '\u203F'..'\u2040'
  ;


fragment  
VARNAME
  :
  JAVA_IDENTIFIER
  //( PN_CHARS_U | '0'..'9') ( PN_CHARS_U | '0'..'9' | '\u00B7' | '\u0300'..'\u036F' | '\u203F'..'\u2040')*
  ;
  
JAVA_IDENTIFIER
  :
  JAVA_LETTER JAVA_LETTER_OR_DIGIT*
  ;

fragment
JAVA_LETTER
  :
  'a'..'z' | 'A'..'Z' | '_'
  ;
  
fragment
JAVA_LETTER_OR_DIGIT
  :
  JAVA_LETTER | '0'..'9'
  ;
  
INTEGER
  :
  '0'..'9'+
  ;

